import {Tank} from "../gameEntity/Tank";
import {Position} from "./Position";
import {Orientation} from "./Orientation";
import {NumberUtil} from "../../utils/NumberUtil";
import {Game} from "../../core/Game";
import {PlayerOption} from "../../core/options/PlayerOption";
import {Bullet} from "../gameEntity/Bullet";
import {IEntity} from "./IEntity";
import {Utils} from "../../utils/Utils";
import {AbstractEntity} from "./AbstractEntity";
import {Constants} from "../../core/Constants";
import {RenderFrameInsertContextHolder} from "./RenderFrameInsertContextHolder";

export class EntityCollection {

  game: Game;
  tanks: Array<Tank> = new Array<Tank>();
  bullets: Array<Bullet> = new Array<Bullet>();

  entityArrays: Array<Array<IEntity>> = new Array<Array<IEntity>>();

  constructor(game: Game) {
    this.game = game;
    this.entityArrays.push(this.tanks, this.bullets);
  }

  /**
   * 进行一次逻辑更新
   */
  updateEntities() {

    this.entityArrays.forEach(entityArray => {
      entityArray.forEach(entity => {
        entity.update();

      });
    });
    this.collideCheck();
    this.destroyCheck();
    this.tankPositionCheck()
    this.bulletRemoveScreenCheck()
  }

  /**
   * 更新玩家的操作 除了操作坦克以外,还有创建坦克的操作请求.
   */
  updateEntitiesControl(options: Map<number, PlayerOption>) {

    let temp: any = {};
    Object.assign(temp, options);

    //创建坦克
    for (let playerId in temp) {

      if (temp[playerId]!.createTankApply) {
        const number = Number(playerId);
        this.tanks.push(new Tank(new Position(number * 100, number * 100), new Orientation(0), 100, number, this.game));

      }
    }


    //修改玩家的操作
    this.tanks.forEach((tank) => {
      const playerOption: PlayerOption = temp[tank.ownerId]!;
      tank.playerKeyBoardState = playerOption.keyboardState;

      //生成子弹
      if (playerOption.keyboardState.spacePress) {
        const currentFrame = this.game.currentFrame;
        if (tank.canShoot(this.game.currentFrame)) {
          tank.onShoot(currentFrame);
          const orientation = tank.logicOrientation.copy();
          orientation.normalize();
          const bulletOrientation = tank.logicOrientation.copy();
          const bulletPosition = tank.logicPosition.copy();

          let vectorX = Math.sin(orientation.getRadian());

          //因为canvas坐标轴y轴是朝下的 所以加负号
          let vectorY = -Math.cos(orientation.getRadian());


          bulletPosition.x += NumberUtil.resolved((Tank.drawSize+Bullet.drawSize) / 2 * vectorX);
          bulletPosition.y += NumberUtil.resolved((Tank.drawSize+Bullet.drawSize) / 2 * vectorY);

          //速度会加上坦克本身的速度
          const speedX = NumberUtil.resolved(Bullet.baseSpeedPerSecond / this.game.logicFramePerSeconds * vectorX + tank.speedX);
          const speedY = NumberUtil.resolved(Bullet.baseSpeedPerSecond / this.game.logicFramePerSeconds * vectorY + tank.speedY);

          const bullet = new Bullet(bulletPosition, bulletOrientation, tank.ownerId, speedX, speedY, this.game);
          this.bullets.push(bullet);




        }
      }
    });
  }

  insertFrameContext:RenderFrameInsertContextHolder|undefined
  /**
   * 更新一次绘制属性 让绘制属性追上逻辑属性
   */
  updateEntitiesDraw() {



    const targetUpdateSpeed = this.game.targetRenderFrames;
    const logicFramesPerSecond = this.game.frameHolder.getLogicFramesPerSecond();
    const renderFramesPerSecond = this.game.frameHolder.getRenderFramesPerSecond();
    //如果逻辑帧速度足够，或者渲染帧速度不够 都选择直接更新到逻辑状态。
    if(logicFramesPerSecond>targetUpdateSpeed||renderFramesPerSecond<targetUpdateSpeed||logicFramesPerSecond>renderFramesPerSecond){
      // console.log('快速同步',logicFramesPerSecond>targetUpdateSpeed,renderFramesPerSecond<targetUpdateSpeed,logicFramesPerSecond>renderFramesPerSecond)

      this.insertFrameContext = undefined
      this.entityArrays.forEach(entityArray => {
        entityArray.forEach((iEntity) => {

          const entity = iEntity as AbstractEntity;
          if (entity != undefined) {
            entity.drawPosition = entity.logicPosition.copy();
            entity.drawOrientation = entity.logicOrientation.copy()
          }
        });
      });
    }else{




      if(this.insertFrameContext ==undefined||this.insertFrameContext!.isFinish()){

        const logicFrameUseTime = 1000/logicFramesPerSecond;//每个逻辑帧所用时间
        const renderFrameUseTime = 1000/renderFramesPerSecond;//每个渲染帧所用时间
        const targetUpdateTime = 1000/this.game.targetRenderFrames;//理想状态下为60帧



        //计算逻辑帧的实际更新时间与预期的目标时间之中 可以插入几个渲染帧
        //比如预期16ms更新一次 但是逻辑帧32ms更新一次 如果渲染帧2ms更新一次 则可以插入8个渲染帧 但是实际测试会卡 建议*2
        let renderFrameCanInsert = (logicFrameUseTime-targetUpdateTime)/renderFrameUseTime*2;

        //renderFrameCanInsert在刚开始的时候可能会计算出Infinity
        if(!(renderFrameCanInsert<50&&renderFrameCanInsert>0)){
          renderFrameCanInsert = 5;
        }



        this.insertFrameContext = new RenderFrameInsertContextHolder(renderFrameCanInsert);
      }
      const context:RenderFrameInsertContextHolder = this.insertFrameContext!



      this.entityArrays.forEach(entityArray => {
        entityArray.forEach((iEntity) => {

          const entity = iEntity as AbstractEntity;

          if (entity != undefined)  {
            //获取位置和方向的目标值
            let targetPosition = context.positionHolder.get(entity)
            if(targetPosition==undefined){
              context.positionHolder.set(entity,entity.logicPosition)
              targetPosition = entity.logicPosition
            }
            let targetOrientation = context.orientationHolder.get(entity)
            if(targetOrientation==undefined){
              context.orientationHolder.set(entity,entity.logicOrientation)
              targetOrientation = entity.logicOrientation
            }



            let positionStep = Position.distance( entity.drawPosition,targetPosition) /context.getCurrentStepPercent();
            positionStep = NumberUtil.resolved(positionStep)
            entity.drawPosition = entity.drawPosition.closeTo(targetPosition, positionStep);

            let orientationStep = Orientation.distanceOfAngle( entity.drawOrientation,targetOrientation)/context.getCurrentStepPercent()
            entity.drawOrientation.rotateToTarget(targetOrientation, orientationStep);



          }
        });
      });
      context.walk()
    }





  }


  getAllEntities(): Array<IEntity> {
    let entitiesArray = new Array<IEntity>();
    return entitiesArray.concat(this.tanks).concat(this.bullets);
  }

  /**
   * 碰撞检测 这里只实现简单的圆形碰撞检测，，因为不用考虑旋转
   */
  collideCheck() {
    let entitiesArray = this.getAllEntities();
    for (let i = 0; i < entitiesArray.length; i++) {
      for (let j = 0; j < entitiesArray.length; j++) {
        if(i==j){
          continue
        }
        const entity1 = entitiesArray[i];
        const entity2 = entitiesArray[j];
        const size1 = entity1.getSize();
        const size2 = entity2.getSize();
        const collideDistance =(size1 + size2)/2;
        let distance =Position.distance(entity1.getPosition(),entity2.getPosition() );
        distance = NumberUtil.resolved(distance);
        if (distance <= collideDistance) {
          entity1.onCollide(entity2);
          entity2.onCollide(entity1);
          if (entity1 instanceof Tank && entity2 instanceof Tank) {
            Tank.onTanksCollide(entity1, entity2);
          }
        }
      }
    }

  }

  /**
   * 检查并移除应该被销毁的实体
   */
  destroyCheck() {

    this.entityArrays.forEach(array => {
      for (let i = 0; i < array.length; i++) {
        const entity = array[i];
        if (entity.shouldRemove()) {
          entity.beforeRemove();
          Utils.removeFromArrayAt(i, array);
           i--;
        }
      }
    });
  }

  /**
   * 子弹从屏幕中消失后进行删除
   */
  bulletRemoveScreenCheck() {
    for (let i = 0; i < this.bullets.length; i++) {
      const bullet = this.bullets[i];
      if (bullet.logicPosition.x < 0 ||
        bullet.logicPosition.x > this.game.canvas.width ||
        bullet.logicPosition.y < 0 ||
        bullet.logicPosition.y > this.game.canvas.height
      ) {
        bullet.beforeRemove();
        Utils.removeFromArrayAt(i, this.bullets);

         i--;

      }
    }
  }

  /**
   * 检测坦克位置 保证其不超过屏幕
   */
  tankPositionCheck(){
    for (let i = 0; i < this.tanks.length; i++) {
      const tank = this.tanks[i];
      //检测左边界
      if (tank.logicPosition.x <= Tank.drawSize/2) {
        if(tank.speedX<0){
          tank.speedX = 0
          tank.logicPosition.x = Tank.drawSize/2
        }
      }

      //检测有边界
      if (tank.logicPosition.x >= this.game.canvas.width-Tank.drawSize/2) {
        if(tank.speedX>0){
          tank.speedX = 0
          tank.logicPosition.x = this.game.canvas.width-Tank.drawSize/2
        }
      }

      //检测上边界
      if (tank.logicPosition.y <=Tank.drawSize/2) {
        if(tank.speedY < 0){
          tank.speedY = 0
          tank.logicPosition.y = Tank.drawSize/2
        }
      }

      //检测下边界
      if (tank.logicPosition.y >= this.game.canvas.height-Tank.drawSize/2) {
        if(tank.speedY>0){
          tank.speedY = 0
          tank.logicPosition.y = this.game.canvas.height-Tank.drawSize/2
        }
      }

    }

  }

}
